#include "alsaSound.h"
#include "udpCommunication.h"

#define UDP_STREAM_AUDIO_PORT	25320
#define UDP_AUDIO_PACKET_LEN 1024

static UdpCommunication udp_audio_svr;

AlsaSound::AlsaSound()
{
	memset(&record, 0x0, sizeof(record));
	fd = -1;
}

AlsaSound::~AlsaSound()
{
}

int AlsaSound::sndwavePrepareWAVParams(WAVContainer_t *wav, int seconds)
{
     assert(wav);

     uint16_t channels = DEFAULT_CHANNELS;
     uint16_t sample_rate = DEFAULT_SAMPLE_RATE;
     uint16_t sample_length = DEFAULT_SAMPLE_LENGTH;
     uint32_t duration_time = seconds;//DEFAULT_DURATION_TIME;

     /* Const */
     wav->header.magic = WAV_RIFF;
     wav->header.type = WAV_WAVE;
     wav->format.magic = WAV_FMT;
     wav->format.fmt_size = LE_INT(DEFAULT_SAMPLE_LENGTH);
     wav->format.format = LE_SHORT(WAV_FMT_PCM);
     wav->chunk.type = WAV_DATA;

     /* User definition */
     wav->format.channels = LE_SHORT(channels);
     wav->format.sample_rate = LE_INT(sample_rate);
     wav->format.sample_length = LE_SHORT(sample_length);

     /* See format of wav file */
	wav->format.blocks_align = LE_SHORT(channels * sample_length / 8);
	wav->format.bytes_p_second = LE_INT((uint16_t)(wav->format.blocks_align) * sample_rate);

	wav->chunk.length = LE_INT(duration_time * (uint32_t)(wav->format.bytes_p_second));
	wav->header.length = LE_INT((uint32_t)(wav->chunk.length) +
         sizeof(wav->chunk) + sizeof(wav->format) + sizeof(wav->header) - 8);

     return 0;
 }

void AlsaSound::sndwaveWriteHeader(WAVContainer_t *wav)
{
	hx280_aud_stream_head head;
	head.len = sizeof(WAVContainer_t);
	memcpy(head.data , wav , sizeof(WAVContainer_t));
	if(ioctl(fd , HX280ENC_SET_AUDIO_HEAD , &head) < 0)
	{
		fprintf(stderr, "Error write wave header error = %s\n",strerror (errno));
	}
}



 

 int AlsaSound::procOneFrame()
 {
	size_t c, frame_size;
	unsigned char * udp_buf;
	unsigned int udp_len;
	unsigned int packet_len;
	int r;
	unsigned char recv_buf[4];
	c = record.chunk_bytes;
	frame_size = c * 8 / record.bits_per_frame;
	if (SNDWAV_ReadPcm(&record, frame_size) != (int)frame_size)
	{
		return -1;
	}

	if (write(fd, record.data_buf, c) != (int)c) {
		fprintf(stderr, "Error SNDWAV_Record[write]/n");
		return -2;
	}

	udp_audio_svr.getPacket(recv_buf , 4);
	udp_buf = (unsigned char * )record.data_buf;
	udp_len = c;
	for (;udp_len > 0;)
	{
		packet_len = udp_len > UDP_AUDIO_PACKET_LEN ? UDP_AUDIO_PACKET_LEN :  udp_len;
		udp_audio_svr.sendPacket(udp_buf , packet_len);
		udp_buf += packet_len;
		udp_len -= packet_len;
		
	}

	return 0;
 }

 int AlsaSound::startRecord(const char *filename, int seconds)
 {
     char devicename[] = "default";
    
     WAVContainer_t wav;

     if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) {
         fprintf(stderr, "Error open: [%s]/n", filename);
         return -1;
     }

     if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) {
         fprintf(stderr, "Error snd_output_stdio_attach/n");
         goto Err;
     }

     if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) {
         fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename);
         goto Err;
     }

     if (sndwavePrepareWAVParams(&wav, seconds) < 0) {
         fprintf(stderr, "Error sndwavePrepareWAVParams/n");
         goto Err;
     }

     if (SNDWAV_SetParams(&record, &wav) < 0) {
         fprintf(stderr, "Error set_snd_pcm_params/n");
         goto Err;
     }
     snd_pcm_dump(record.handle, record.log);

	 sndwaveWriteHeader(&wav);

	 udp_audio_svr.initServer(UDP_STREAM_AUDIO_PORT);
	 return 0;

 Err:
     stopRecord();
     return -1;
 }


 int AlsaSound::stopRecord()
 {
	 snd_pcm_drain(record.handle);
     free(record.data_buf);
     snd_output_close(record.log);
     snd_pcm_close(record.handle);
	 close(fd);
 }

 
void* AlsaSound::exec(void *arg)
{
	AlsaSound* p = (AlsaSound *)arg;
	p->run();
	return NULL;
}

void AlsaSound::run()
{
	while(1)
	{
		procOneFrame();
	}
}

 void AlsaSound::startThread()
 {
	 pthread_create(&threadID, NULL, exec, this);
 }
